package com.pub.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;


/**
*

Title:


*
Description:


*
Copyright: flashman.com.cn Copyright (c) 2005


*
Company: flashman.com.cn


* @author: jeffzhu
* @version 1.0
*/
public class CharUtils 
{
	private static byte[] btISO8859_1ForC2 = {
		(byte)0xA0, (byte)0xA1, (byte)0xA2, (byte)0xA3, (byte)0xA4, (byte)0xA5, (byte)0xA6, (byte)0xA7, (byte)0xA8, (byte)0xA9, (byte)0xAA,(byte)0xAB, (byte)0xAC, (byte)0xAD, (byte)0xAE,(byte)0xAF, 
		(byte)0xB0, (byte)0xB1, (byte)0xB2, (byte)0xB3, (byte)0xB4, (byte)0xB5, (byte)0xB6, (byte)0xB7, (byte)0xB8, (byte)0xB9, (byte)0xBA,(byte)0xBB, (byte)0xBC, (byte)0xBD, (byte)0xBE,(byte)0xBF};
	
	private static byte[] btISO8859_1ForC3 = {
		(byte)0xC0, (byte)0xC1, (byte)0xC2, (byte)0xC3, (byte)0xC4, (byte)0xC5, (byte)0xC6, (byte)0xC7, (byte)0xC8, (byte)0xC9, (byte)0xCA,(byte)0xCB, (byte)0xCC, (byte)0xCD, (byte)0xCE,(byte)0xCF, 
		(byte)0xD0, (byte)0xD1, (byte)0xD2, (byte)0xD3, (byte)0xD4, (byte)0xD5, (byte)0xD6, (byte)0xD7, (byte)0xD8, (byte)0xD9, (byte)0xDA,(byte)0xDB, (byte)0xDC, (byte)0xDD, (byte)0xDE,(byte)0xDF,
		(byte)0xE0, (byte)0xE1, (byte)0xE2, (byte)0xE3, (byte)0xE4, (byte)0xE5, (byte)0xE6, (byte)0xE7, (byte)0xE8, (byte)0xE9, (byte)0xEA,(byte)0xEB, (byte)0xEC, (byte)0xED, (byte)0xEE,(byte)0xEF, 
		(byte)0xF0, (byte)0xF1, (byte)0xF2, (byte)0xF3, (byte)0xF4, (byte)0xF5, (byte)0xF6, (byte)0xF7, (byte)0xF8, (byte)0xF9, (byte)0xFA,(byte)0xFB, (byte)0xFC, (byte)0xFD, (byte)0xFE,(byte)0xFF

	};

	private static byte[][] btUTF8Filter 	= {{(byte)0xEF, (byte)0xBF, (byte)0xBD}, {(byte)0xE2, (byte)0x84, (byte)0xA2}};
	
	private static Charset CSTarget;
	private ByteBuffer BBCache;
	private CharBuffer CBBuffer;

	private static HashSet<Integer> HSReturnFlag;
	
	private static String STRSourceEncoding;
	private static String STRTargetEncoding;
	
	public CharUtils(String strSourceEncoding, String strTargetEncoding)
	{
		CharUtils.STRSourceEncoding = strSourceEncoding;
		CharUtils.STRTargetEncoding = strTargetEncoding;
		
		CharUtils.CSTarget 		= Charset.forName(CharUtils.STRSourceEncoding);
		CharUtils.HSReturnFlag 	= new HashSet<Integer>();
		
	}
	
	
	/**
	 * convert from ISO-8859-1 to GB2312
	 * @param text
	 * @return
	 */
	public String ISO2GB(String text) 
	{
	    String result = "";
	    try {
	      result = new String(text.getBytes("ISO-8859-1"), "GB2312");
	    }
	    catch (UnsupportedEncodingException ex) {
	      result = ex.toString();
	    }
	    return result;
	}

  /**
   * convert from GB2312 to ISO-8859-1
   * @param text
   * @return
   */
  public String GB2ISO(String text) {
    String result = "";
    try {
      result = new String(text.getBytes("GB2312"), "ISO-8859-1");
    }
    catch (UnsupportedEncodingException ex) {
      ex.printStackTrace();
    }
    return result;
  }
  /**
   * Utf8URL
   * @param s
   * @return
   */
  public String Utf8URLencode(String text) {
    StringBuffer result = new StringBuffer();

    for (int i = 0; i < text.length(); i++) {

      char c = text.charAt(i);
      if (c >= 0 && c <= 255) {
        result.append(c);
      }else {

        byte[] b = new byte[0];
        try {
          b = Character.toString(c).getBytes("UTF-8");
        }catch (Exception ex) {
        }

        for (int j = 0; j < b.length; j++) {
          int k = b[j];
          if (k < 0) k += 256;
          result.append("%" + Integer.toHexString(k).toUpperCase());
        }

      }
    }

    return result.toString();
  }

  /**
   * Utf8URL decode
   * @param text
   * @return
   */
  public String Utf8URLdecode(String text) {
    String result = "";
    int p = 0;

    if (text!=null && text.length()>0){
      text = text.toLowerCase();
      p = text.indexOf("%e");
      if (p == -1) return text;

      while (p != -1) {
        result += text.substring(0, p);
        text = text.substring(p, text.length());
        if (text == "" || text.length() < 9) return result;

        result += CodeToWord(text.substring(0, 9));
        text = text.substring(9, text.length());
        p = text.indexOf("%e");
      }

    }

    return result + text;
  }

  /**
   * utf8URL CodeToWord
   * @param text
   * @return
   */
  private String CodeToWord(String text) {
    String result;

    if (Utf8codeCheck(text)) {
      byte[] code = new byte[3];
      code[0] = (byte) (Integer.parseInt(text.substring(1, 3), 16) - 256);
      code[1] = (byte) (Integer.parseInt(text.substring(4, 6), 16) - 256);
      code[2] = (byte) (Integer.parseInt(text.substring(7, 9), 16) - 256);
      try {
        result = new String(code, "UTF-8");
      }catch (UnsupportedEncodingException ex) {
        result = null;
      }
    }
    else {
      result = text;
    }

    return result;
  }

  public static boolean isValidUtf8(byte[] b, int aMaxCount) 
  {
	  int j, lLen = b.length, lCharCount = 0;
	  byte lByte;
	  
	  for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount) {
		  lByte = b[i++]; //to fast operation, ++ now, ready for the following for(;;)
		  if (lByte >= 0) 
			  continue; //>=0 is normal ascii
		  if (lByte < (byte) 0xc0 || lByte > (byte) 0xfd)
			  return false;
		  int lCount = lByte >= (byte) 0xfc ? 5 
				  		: lByte >= (byte) 0xf8 ? 4 
				  				: lByte >= (byte) 0xf0 ? 3 
				  						: lByte >= (byte) 0xe0 ? 2 
				  								: 1;
	      
		  if (i + lCount > lLen) 
	    	  return false;
	      for (j = 0; j < lCount; ++j, ++i)
	    	  if (b[i] >= (byte) 0xc0 || b[i] < (byte) 0x80)
	    		  return false;
	  }
	  
	  return true;
  }

  	public static boolean isHaveClassUtf8(byte[] b, int aMaxCount) 
  	{
  		int lLen = b.length, lCharCount = 0;
		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount) {
			byte lByte = b[i++]; //to fast operation, ++ now, ready for the following for(;;)
			if (lByte >= 0 || i >= lLen) 
				continue; //>=0 is normal ascii
			if (lByte == (byte) 0xc2 && b[i] >= (byte) 0xa0 && b[i] <= (byte) 0xbf || lByte == (byte) 0xc3 && b[i] >= (byte) 0x80 && b[i] <= (byte) 0xbf)
				return true;
		}
		  
		return false;
  	}
  
  	public static boolean isShiftJIS(byte[] b, int maxLen) 
  	{
  		int lLen = b.length, lCharCount = 0;
  		
		for (int i = 0; i < lLen && lCharCount < maxLen; lCharCount++) {
			byte lByte = b[i++]; //to fast operation, ++ now, ready for the following for(;;)
			if (lByte >= 0 || lByte > (byte)0xA0 && lByte < (byte)0xE0 || i > lLen){
				continue; //>=0 is normal ascii
			}
			
			if(i < maxLen && (lByte >= (byte)0x81 && lByte <= (byte)0x9F || lByte >= (byte)0xE0 && lByte <= (byte)0xEF || lByte >= (byte)0xF0 && lByte <= (byte)0xFC) && (b[i] >= (byte)0x40 && b[i] <= (byte)0x7E || b[i] >= (byte)0x80 && b[i] <= (byte)0xFC)){
				i++;

				continue;
			}else{
				return false;
			}
		}
		
		return true;
  	}
  	
  	public static boolean isShiftJIS(byte[] b, int maxLen, ArrayList<ArrayList<Integer>> outErrorInfo) 
  	{
  		int lLen = b.length, lCharCount = 0;
		for (int i = 0; i < lLen && lCharCount < maxLen; ++lCharCount) {
			byte lByte = b[i++]; //to fast operation, ++ now, ready for the following for(;;)
			if (lByte >= 0 || lByte > (byte)0xA0 && lByte < (byte)0xE0 || i > lLen){
				continue; //>=0 is normal ascii
			}
			
			if(i < maxLen && (lByte >= (byte)0x81 && lByte <= (byte)0x9F || lByte >= (byte)0xE0 && lByte <= (byte)0xEF || lByte >= (byte)0xF0 && lByte <= (byte)0xFC) && (b[i] >= (byte)0x40 && b[i] <= (byte)0x7E || b[i] >= (byte)0x80 && b[i] <= (byte)0xFC)){
				i++;
				continue;
			}else{
				ArrayList<Integer> alCache = new ArrayList<Integer>();
				alCache.add(new Byte(lByte).intValue()); //first byte
				alCache.add(new Byte(b[i]).intValue());// second byte
				
				outErrorInfo.add(alCache);
				return false;
			}
		}
		
		return true;
  	}
  	
  	public byte[] btFilterForJP(byte[] b, int aMaxCount, byte[][] btTargert) 
  	{
  		int j, c, iLen, k = 0, lLen = b.length, lCharCount = 0;
  		
  		boolean isMatch;
  		
  		byte[] btReturn = new byte[b.length];
  		byte lByte;
  		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte >= 0 || lByte > (byte)0xA0 && lByte < (byte)0xE0){// one byte
				if(lByte > (byte)0x1F && lByte < (byte)0x7F || lByte > (byte)0xA0 && lByte < (byte)0xE0 || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				}else
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				
				continue; //>=0 is normal ascii
			}
			
			if(i == lLen)
				continue;
			
			j 		= 0;
			iLen 	= 0;
			
			for (c = 0; c < btTargert.length; c++){
				isMatch = true;
				iLen 	= btTargert[c].length;
				
				for (j = 0; j < btTargert[c].length; j++){
					if ((i + j) >= lLen || b[i + j] != btTargert[c][j]){
						isMatch = false;
						
						break;
					}
				}
				
				if(isMatch)
					break;
			}
			
			if(j != 0 && j == iLen){//filter
				i += j - 1;
				
				CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				continue;
			}else{// two byte
				if((lByte >= (byte)0x81 && lByte <= (byte)0x9F || lByte >= (byte)0xE0 && lByte <= (byte)0xEF || lByte >= (byte)0xF0 && lByte <= (byte)0xFC) && (b[i + 1] >= (byte)0x40 && b[i + 1] <= (byte)0x7E || b[i + 1] >= (byte)0x80 && b[i + 1] <= (byte)0xFC)){
					i++;
					
					btReturn[k] = lByte;
					k++;
					
					btReturn[k] = b[i];
					k++;
				}else
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public byte[] btFilterForJP(byte[] b, int aMaxCount) 
  	{
  		int k = 0, lLen = b.length, lCharCount = 0;
  		
  		byte[] btReturn = new byte[b.length];
  		byte lByte;
  		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte >= 0 || lByte > (byte)0xA0 && lByte < (byte)0xE0){// one byte
				if(lByte > (byte)0x1F && lByte < (byte)0x7F || lByte > (byte)0xA0 && lByte < (byte)0xE0 || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				}else
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				
				continue; //>=0 is normal ascii
			}
			
			if(i == lLen)
				continue;
			
			// two byte
			if((lByte >= (byte)0x81 && lByte <= (byte)0x9F || lByte >= (byte)0xE0 && lByte <= (byte)0xEF || lByte >= (byte)0xF0 && lByte <= (byte)0xFC) && (b[i + 1] >= (byte)0x40 && b[i + 1] <= (byte)0x7E || b[i + 1] >= (byte)0x80 && b[i + 1] <= (byte)0xFC)){
				i++;
				
				btReturn[k] = lByte;
				k++;
				
				btReturn[k] = b[i];
				k++;
			}else
				CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public static boolean isASCII(String strSource)
   	{
   		boolean isReturn = true;
   		
        char[] cs = strSource.toCharArray();  
        for (int i = 0; i < cs.length; i++)   {  
        	if(!(cs[i] < 128)){
				isReturn = false;
				break; 
			}  
		}
        
   		return isReturn;
   	}
   	
   	public static boolean isChinese(String strSource)
   	{
   		boolean isReturn = true;
   		
        char[] cs = strSource.toCharArray();  
        for (int i = 0; i < cs.length;   i++)   {  
			if(!(cs[i] > 0x80)){
				isReturn = false;
				break;
			}  
		}
        
   		return isReturn;
   	}
   	
  	public static byte[] btConvertToISO8859_1(byte[] b, int aMaxCount) 
  	{
  		int k = 0, lLen = b.length, lCharCount = 0;
  		
  		byte[] btReturn = new byte[b.length];
  		byte lByte;
  		
		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount) {
			lByte = b[i++]; //to fast operation, ++ now, ready for the following for(;;)
			if (lByte >= 0){
				btReturn[k] = lByte;
				k++;
				
				continue; //>=0 is normal ascii
			}
			
			if(i >= lLen)
				continue;
			
			if (lByte == (byte) 0xc2 && b[i] >= (byte) 0xa0 && b[i] <= (byte) 0xbf){
				btReturn[k] = CharUtils.btISO8859_1ForC2[b[i] - (byte)0xa0];
				k++;

				i++;
			}else if (lByte == (byte) 0xc3 && b[i] >= (byte) 0x80 && b[i] <= (byte) 0xbf){
				btReturn[k] = CharUtils.btISO8859_1ForC3[b[i] - (byte)0x80];
				k++;
				
				i++;
			}else{
				btReturn[k] = lByte;
				k++;
			}
		}
		
		return Arrays.copyOfRange(btReturn, 0, k);
	}
  	
  	public static boolean isContains(byte[] btIn, byte[] btSearch)
  	{
  		boolean isReturn = false;
  		
  		int i, j;
  		
  		for (i = 0; i < btIn.length; i++) {
  			for (j = 0; j < btSearch.length; j++){
				if ((i + j) >= btIn.length || btIn[i + j] != btSearch[j])
					break;
			}
  			
  			if(j != 0 && j == btSearch.length){
  				isReturn = true;
  				break;
  			}
  		}
  		
  		return isReturn;
  	}
  	
  	public static byte[] btTailTrim(byte[] btSource)
  	{
  		int i, j = 0;
  		byte btSpace = 0x20;
  		
  		for (i = btSource.length - 1; i > -1; i--) {
  			if(btSource[i] != btSpace){
  				break;
  			}else{
  				j = i;
  			}
  		}
  		
  		if(j > 0)
  			return Arrays.copyOfRange(btSource, 0, j);
  		else
  			return btSource;
  	}
  	
  	public static byte[] btHeadTrim(byte[] btSource)
  	{
  		int i, j = 0;
  		byte btSpace = 0x20;
  		
  		for (i = 0; i < btSource.length; i++) {
  			j = i;
  			
  			if(btSource[i] != btSpace)
  				break;
  		}
  		
  		if(j > 0)
  			return Arrays.copyOfRange(btSource, j, btSource.length);
  		else
  			return btSource;
  	}
  	
  	public static byte[] btTrim(byte[] btSource)
  	{
  		return btTailTrim(btHeadTrim(btSource));
  	}
  	
  	public static byte[] btNotFlagFilterForEN(byte[] b, int aMaxCount, byte[] btTargert) 
  	{
  		int j, k = 0, lLen = b.length, lCharCount = 0;
  		
  		byte[] btReturn = new byte[b.length];
  		byte lByte;
  		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte >= 0){
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				}
				
				continue; //>=0 is normal ascii
			}

			if(i >= lLen)
				continue;
			
			for (j = 0; j < btTargert.length; j++){
				if ((i + j) >= lLen || b[i + j] != btTargert[j])
					break;
			}
			
			if(j != 0 && j == btTargert.length){
				i += j - 1;
				continue;
			}else{
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				}
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public byte[] btFilterForEN(byte[] b, int aMaxCount, byte[] btTargert) 
  	{
  		int j, k = 0, lLen = b.length, lCharCount = 0;
  		
  		byte[] btReturn = new byte[b.length];
  		byte lByte;
  		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte > 0){
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
			
				}else
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				
				continue; //>=0 is normal ascii
			}
	
			if(i >= lLen)
				continue;
			
			for (j = 0; j < btTargert.length; j++){
				if ((i + j) >= lLen || b[i + j] != btTargert[j])
					break;
			}
			
			if(j != 0 && j == btTargert.length){
				i += j - 1;
				
				CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				continue;
			}else{
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				}else
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public static byte[] btFilterForEN(byte[] b, int aMaxCount, byte[][] btTargert) 
  	{
  		int j, c, iLen, k = 0, lLen = b.length, lCharCount = 0;
  		
  		boolean isMatch;
  		byte lByte;
  		
  		byte[] btReturn = new byte[b.length];
		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte >= 0){
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				
				}else{
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				}
				
				continue; //>=0 is normal ascii
			}
			
			if(i >= lLen)
				continue;
			
			j 		= 0;
			iLen 	= 0;
			
			for (c = 0; c < btTargert.length; c++){
				isMatch = true;
				iLen 	= btTargert[c].length;
				
				for (j = 0; j < btTargert[c].length; j++){
					if ((i + j) >= lLen || b[i + j] != btTargert[c][j]){
						isMatch = false;
						
						break;
					}
				}
				
				if(isMatch)
					break;
			}
			
			if(j != 0 && j == iLen){
				i += j - 1;
				
				CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				continue;
			}else{
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				}else{
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				}
					
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public static byte[] btFilterForEN(byte[] b, int aMaxCount) 
  	{
  		int k = 0, lLen = b.length, lCharCount = 0;
  		
   		byte lByte;
  		
  		byte[] btReturn = new byte[b.length];
		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte >= 0){
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				
				}else{
					CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				}
				
				continue; //>=0 is normal ascii
			}
			
			if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
				btReturn[k] = lByte;
				k++;
			}else{
				CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public static byte[] btFilterNoFlagForEN(byte[] b, int aMaxCount) 
  	{
  		int k = 0, lLen = b.length, lCharCount = 0;
  		
   		byte lByte;
  		
  		byte[] btReturn = new byte[b.length];
		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			if (lByte >= 0){
				if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
					btReturn[k] = lByte;
					k++;
				
				}
				
				continue; //>=0 is normal ascii
			}
			
			if(lByte >= (byte)0x20 && lByte <= (byte)0x7E || lByte >= (byte)0xA0 && lByte <= (byte)0xFF || lByte == (byte)0x09 || lByte == (byte)0x0A || lByte == (byte)0x0D){
				btReturn[k] = lByte;
				k++;
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public static byte[] btFilterCharsForEN(byte[] b, int aMaxCount, byte[][] btTargert) 
  	{
  		int j, c, iLen, k = 0, lLen = b.length, lCharCount = 0;
  		
  		boolean isMatch;
  		byte lByte;
  		
  		byte[] btReturn = new byte[b.length];
		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			j 		= 0;
			iLen 	= 0;
			
			for (c = 0; c < btTargert.length; c++){
				isMatch = true;
				iLen 	= btTargert[c].length;
				
				for (j = 0; j < btTargert[c].length; j++){
					if ((i + j) >= lLen || b[i + j] != btTargert[c][j]){
						isMatch = false;
						
						break;
					}
				}
				
				if(isMatch)
					break;
			}
			
			if(j != 0 && j == iLen){
				i += j - 1;
				
				CharUtils.HSReturnFlag.add(5);	//--> 5 : have remove
				continue;
			}else{
				btReturn[k] = lByte;
				k++;
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	public static byte[] btFilterCharsNoFlagForEN(byte[] b, int aMaxCount, byte[][] btTargert) 
  	{
  		int j, c, iLen, k = 0, lLen = b.length, lCharCount = 0;
  		
  		boolean isMatch;
  		byte lByte;
  		
  		byte[] btReturn = new byte[b.length];
		
  		for (int i = 0; i < lLen && lCharCount < aMaxCount; ++lCharCount, i++) {
			lByte = b[i]; //to fast operation, ++ now, ready for the following for(;;)
			
			j 		= 0;
			iLen 	= 0;
			
			for (c = 0; c < btTargert.length; c++){
				isMatch = true;
				iLen 	= btTargert[c].length;
				
				for (j = 0; j < btTargert[c].length; j++){
					if ((i + j) >= lLen || b[i + j] != btTargert[c][j]){
						isMatch = false;
						
						break;
					}
				}
				
				if(isMatch)
					break;
			}
			
			if(j != 0 && j == iLen){
				i += j - 1;
				
				continue;
			}else{
				btReturn[k] = lByte;
				k++;
			}
		}

 		return Arrays.copyOfRange(btReturn, 0, k);
  	}
  	
  	/** auto check and fix string for US. encoding scope in ISO8859-1 and UTF-8. 
     * 
     * @param btSource
     * @return filter string
  	 * @throws UnsupportedEncodingException 
     */
  	public String strAutoCheckForUS(byte[] btSource) throws UnsupportedEncodingException
  	{
 		CharUtils.HSReturnFlag.clear();
 		
  		if(CharUtils.isValidUtf8(btSource, btSource.length)){
  			CharUtils.HSReturnFlag.add(1);	//--> 1 : is UTF-8 encoding
  			
  			return new String(CharUtils.btFilterCharsForEN(btSource, btSource.length, CharUtils.btUTF8Filter), "UTF-8");
		}else{
			CharUtils.HSReturnFlag.add(2);	//--> 2 : is not UTF-8 encoding

			if(CharUtils.isHaveClassUtf8(btSource, btSource.length)){
				btSource = CharUtils.btConvertToISO8859_1(btSource, btSource.length);
				
				CharUtils.HSReturnFlag.add(3);	//--> 3 : is not UTF-8 encoding, but have UTF8 char.
			}else{
				CharUtils.HSReturnFlag.add(4);	//--> 4 : is not UTF-8 encoding, but have not UTF8 char.
			}
		}
		
		btSource = CharUtils.btFilterForEN(btSource, btSource.length);
		btSource = this.btConvertEncoding(btSource);
		
		return new String(btSource, CharUtils.STRTargetEncoding);
 	}
  	
  	/** auto check and fix string for US. encoding scope in ISO8859-1 and UTF-8. 
     * 
     * @param btSource
     * @return filter string
  	 * @throws UnsupportedEncodingException 
     */
  	public String strMoreAutoCheckForJP(byte[] btSource) throws UnsupportedEncodingException
  	{
 		CharUtils.HSReturnFlag.clear();
 		
 		btSource = CharUtils.btFilterCharsForEN(btSource, btSource.length, CharUtils.btUTF8Filter);
  		if(CharUtils.isShiftJIS(btSource, btSource.length, null)){
  			CharUtils.HSReturnFlag.add(1);	//--> 1 : is SJIS encoding
  		}else{
  			CharUtils.HSReturnFlag.add(2);	//--> 2 : is not SJIS encoding
 		}
	
		btSource = this.btFilterForJP(btSource, btSource.length);
  		btSource = this.btConvertEncoding(btSource);
		
  		btSource = CharUtils.btFilterCharsForEN(btSource, btSource.length, CharUtils.btUTF8Filter);
		
		return new String(btSource, CharUtils.STRTargetEncoding);
  	}
  	
  	/** auto check and fix string for US. encoding scope in ISO8859-1 and UTF-8. 
     * 
     * @param btSource
     * @return filter string
  	 * @throws UnsupportedEncodingException 
     */
  	public String strMoreAutoCheckForUS(byte[] btSource) throws UnsupportedEncodingException
  	{
 		CharUtils.HSReturnFlag.clear();
 		
 		btSource = CharUtils.btFilterCharsForEN(btSource, btSource.length, CharUtils.btUTF8Filter);
 		
  		if(CharUtils.isValidUtf8(btSource, btSource.length)){
			CharUtils.HSReturnFlag.add(1);	//--> 1 : is UTF-8 encoding
			return new String(btSource, "UTF-8");
		}else{
			CharUtils.HSReturnFlag.add(2);	//--> 2 : is not UTF-8 encoding
			
			if(CharUtils.isHaveClassUtf8(btSource, btSource.length)){
				btSource = CharUtils.btConvertToISO8859_1(btSource, btSource.length);
				
				CharUtils.HSReturnFlag.add(3);	//--> 3 : is not UTF-8 encoding, but have UTF8 char.
			}else{
				CharUtils.HSReturnFlag.add(4);	//--> 4 : is not UTF-8 encoding, but have not UTF8 char.
			}
		}
  		
  		btSource = CharUtils.btFilterForEN(btSource, btSource.length);
		
		btSource = this.btConvertEncoding(btSource);
		
		btSource = CharUtils.btFilterCharsForEN(btSource, btSource.length, CharUtils.btUTF8Filter);
		
		return new String(btSource, CharUtils.STRTargetEncoding);
  	}
  	
  	/** auto check and fix string for US. encoding scope in ISO8859-1 and UTF-8. 
     * 
     * @param btSource
     * @return filter string
  	 * @throws UnsupportedEncodingException 
     */
  	public String strMoreAutoCheckNoFlagForUS(byte[] btSource) throws UnsupportedEncodingException
  	{
 		btSource = CharUtils.btFilterCharsNoFlagForEN(btSource, btSource.length, CharUtils.btUTF8Filter);

  		if(CharUtils.isValidUtf8(btSource, btSource.length)){
			return new String(btSource, "UTF-8");
		}else{
			if(CharUtils.isHaveClassUtf8(btSource, btSource.length)){
				btSource = CharUtils.btConvertToISO8859_1(btSource, btSource.length);
			}
		}
 		
 		btSource = this.btConvertEncoding(btSource);
		
		btSource = CharUtils.btFilterCharsNoFlagForEN(btSource, btSource.length, CharUtils.btUTF8Filter);
		
		return new String(btSource, CharUtils.STRTargetEncoding);
  	}
  	
  	public HashSet<Integer> hsGetHandleFlag()
  	{
  		return CharUtils.HSReturnFlag;
  	}
  	
  	
   	
	/**
	 * is valid utf8 ？
	 * @param text
	 * @return
	 */
	private boolean Utf8codeCheck(String text)
	{
	    String sign = "";
	    if (text.startsWith("%e"))
	    	for (int i = 0, p = 0; p != -1; i++) {
	    		p = text.indexOf("%", p);
	    		if (p != -1)
	    			p++;
	    		sign += p;
	    	}
	    return sign.equals("147-1");
	}

	/**
	 * is Utf8Url encoding ?
	 * @param text
	 * @return
	 */
	public boolean isUtf8Url(String text) 
	{
		text = text.toLowerCase();
		int p = text.indexOf("%");
		if (p != -1 && text.length() - p > 9) {
			text = text.substring(p, p + 9);
		}
		return Utf8codeCheck(text);
	}

	/**
	 * encoding convert
	 * @param btSource  	# source byte array
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public String strConvertEncoding(byte[] btSource) throws UnsupportedEncodingException 
	{
		BBCache		= ByteBuffer.wrap(btSource);
		CBBuffer		= CharUtils.CSTarget.decode(BBCache);

		return new String(CBBuffer.toString().getBytes(), CharUtils.STRTargetEncoding);
	}
	
	/**
	 * encoding convert
	 * @param btSource  	# source byte array
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public byte[] btConvertEncoding(byte[] btSource) throws UnsupportedEncodingException 
	{
		BBCache 	= ByteBuffer.wrap(btSource);
		CBBuffer		= CharUtils.CSTarget.decode(BBCache);

		return CBBuffer.toString().getBytes(CharUtils.STRTargetEncoding);
	}
	
	/**
	 * encoding convert
	 * @param btSource  	# source byte array
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public byte[] btShiftJIStoUTF8(byte[] btSource) throws UnsupportedEncodingException 
	{
		if(!CharUtils.isValidUtf8(btSource, btSource.length) && !CharUtils.isShiftJIS(btSource, btSource.length)){
			BBCache.clear();
			CBBuffer.clear();
			
			BBCache 	= ByteBuffer.wrap(btSource);
			CBBuffer	= CharUtils.CSTarget.decode(BBCache);

			return CBBuffer.toString().getBytes(CharUtils.STRTargetEncoding);
		}else
			return btSource;
	}
	
	public boolean isEncodeString(String keyword)
	{
		int pos = keyword.indexOf("%");
		if(pos != -1){
			pos = keyword.indexOf("%", pos);
			if(pos != -1){// have two %
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * test
	 * @param args
	 */
	public static void main(String[] args) 
	{
	  //byte[] b1 = {(byte)0xA1, (byte)0xA2, (byte)0xA3, (byte)0xEF, (byte)0xBF, (byte)0xBD, (byte)0xB1, (byte)0xB2, (byte)0xB3};
	 // byte[] f1 = {(byte)0xEF, (byte)0xBF, (byte)0xBD};
	 // byte[][] btUTF8Filter 	= {{(byte)0xEF, (byte)0xBF, (byte)0xBD}, {(byte)0xE2, (byte)0x84, (byte)0xA2}};
	  //byte[] b2 = {(byte)0x80, (byte)0xEF, (byte)0xBF, (byte)0xBD,(byte)0x92, (byte)0xA9, (byte)0x93, (byte)0xFA, (byte)0xE2, (byte)0x84, (byte)0xA2, (byte)0x83, (byte)0x5C};
	  byte[] b2 = {(byte)0xEF, (byte)0xBF, (byte)0xBD,(byte)0xB1,(byte)0xC2,(byte)0x99};
	  byte[] b1 = {(byte)0x20,(byte)0xC2,(byte)0x20};
	  byte[] b3 = {(byte)0xE3, (byte)0x83, (byte)0x91 };
	  byte[] b4 = {(byte)0x44, (byte)0x56, (byte)0x64 };
	  
	  //CharUtils charTools = new CharUtils("ISO8859-1", "UTF-8");
	  CharUtils charTools = new CharUtils("UTF-8", "EUC-JP");
	 
	  try {
		  String tmp = "% ce % b9 % b9 % d4 % a5 % b0 % a5 % c3 % a5 % ba";
		  tmp = "% e5 % a4 % a7 % e5 % ad % a6 % e3 % 83 % a9 % e3 % 83 % b3 % e3 % 82 % ad % e3 % 83 % b3 % e3 % 82 % b0 % e3 % 80%80";
		  System.out.println("8888888888888888== = " + URLDecoder.decode(tmp.replaceAll(" ", ""), "EUC-JP"));
		  
		  
		  tmp = "% e3 % 83 % a2 % e3 % 83 % b3 % e3 % 82 % b9 % e3 % 82 % bf % e3 % 83 % bc % e3 % 83%8 f % e3 % 83 % b3 % e3 % 82 % bf ";
		  tmp = "% e5 % a4 % a7 % e5 % ad % a6 % e3 % 83 % a9 % e3 % 83 % b3 % e3 % 82 % ad % e3 % 83 % b3 % e3 % 82 % b0 % e3 % 80%80";
		  
		  if(charTools.isEncodeString(tmp)){
			  System.out.println("3333333333333333== = ");
			  
			  tmp = tmp.replaceAll("%", "").replaceAll(" ", "");
			  
			  System.out.println("4444444444444== = " + tmp);
			  
		  }else{
			  System.out.println("7777777777777777====== = ");
		  }
		  
		  
		 // System.out.println("out===222============== = " + StringUtils.Bytes2HexString(charTools.btConvertEncoding(b4)));
		  
		  //System.out.println("out===fffffff============== = " + CharUtils.isShiftJIS(b3, b3.length));
		  
		  /*CharUtils charTools = new CharUtils("MS932", "UTF-8");
		  charTools.btConvertEncoding("".getBytes());
		  
		  InputStream inStream;
		  inStream 	= new FileInputStream("E:/w.txt");
  		
		  int bytesum  = 0; 
		  int byteread = 0; 
		  byte[] buffer 	= new byte[1444]; 
	    
		  ArrayList<ArrayList<Integer>> alOutErrorInfo = new ArrayList<ArrayList<Integer>>();
		  
		  
		  while ((byteread = inStream.read(buffer)) != -1) { 
			  bytesum += byteread;
			  
			  if(!CharUtils.isShiftJIS(buffer, byteread, alOutErrorInfo))
				  System.out.println("------------------>" + bytesum);
			   
		  }
		  
		 inStream.close();
		  
		 ArrayList<Integer> a;
		 
		 System.out.println("------error size ------------>" + alOutErrorInfo.size()); 
		 if(alOutErrorInfo.size() > 0){
			 for(int i = 0; i < alOutErrorInfo.size(); i++){
				 a = alOutErrorInfo.get(i);
				 System.out.println("i ----------------------------> " + i);
				 for(int j = 0; j < a.size(); j++){
					 System.out.println("j ---> " + Integer.toHexString(a.get(j)));
				 }
			 }
		 }
		 */
		  
		//Charset cs_sjis 	= Charset.forName("ISO8859-1");
		//ByteBuffer bb_sjis 	= ByteBuffer.wrap( b2);
		///CharBuffer cb 		= cs_sjis.decode( bb_sjis );
		//byte[] bt=bb_sjis.array();
		
		//char[] ch = cb.array();
		//System.out.println("out===fffffff============== = " + StringUtils.Bytes2HexString(CharUtils.btTrim(b1)));
		//System.out.println("out===fffffff============== = " + StringUtils.Bytes2HexString(cb.toString().getBytes("UTF8")));
		//System.out.println("out===fcccccc============== = " + StringUtils.Bytes2HexString(charTools.btConvertEncoding(b2)));
		//System.out.println("out hex = " + StringUtils.Bytes2HexString(charTools.strMoreAutoCheckForUS(b2).getBytes("UTF8")));
		
	} catch (Exception e) {
		
		e.printStackTrace();
	}
	  

  }

}